﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "GcmpModel.h"

namespace gcmp
{
    /// \brief 检查非模型文件完整性选项
    enum class NonModelFilesCheckOption : int32_t
    {
        None                = 0,        /// < 不进行文件完整性检测。
        Family              = 1 << 0,   /// < 只检测族文件完整性。
        Material            = 1 << 1,   /// < 只检测材质文件完整性。
    };

    class IDocument;

    /// \brief 申请访问文档的ProjectContainer当中的文件或文件夹。
    ///
    /// 在对象生命周期内起作用，构造时申请，析构时将访问权交还。
    /// 需要使用的场景：
    ///     1)向ProjectContainer移入文件，需要申请对目标文件夹的权限。
    ///     2)从ProjectContainer移出文件，需要申请被移除文件的权限。
    ///     3)在ProjectContainer中重命名已有文件，需要申请所在文件夹和文件的权限。
    ///
    /// \note 目前只对族和材质相关路径做了限制
    class GCMP_MODEL_EXPORT AccessDocumentProjectContainer
    {
    public:
        /// \brief 构造函数。仅申请对文件或者路径本身的权限。
        /// \param pDocument 文档指针
        /// \param path 文件或者文件夹全路径
        AccessDocumentProjectContainer(const IDocument * pDocument, const std::wstring & path);

        /// \brief 构造函数。申请文件夹内容的权限
        /// \param pDocument 文档指针
        /// \param directoryPath 文件夹全路径
        /// \param recursively 是否递归
        AccessDocumentProjectContainer(const IDocument * pDocument, const std::wstring & directoryPath, bool recursively);

        /// \brief 析构函数。归还权限。
        ~AccessDocumentProjectContainer();
    private:
        const IDocument * m_pDocument;
        std::wstring m_path;
        int m_type;
    };

    /// \brief 文档路径工具
    /// 
    /// 获取打开文档运行时的常用路径和名字（如族路径、临时文件路径等）
    class GCMP_MODEL_EXPORT DocumentPathUtils
    {
    public:
        /// \brief 获取文档中载入的族文件所在文件夹的路径
        /// \param pDocument 文档的指针
        /// \return 文件路径
        static std::wstring GetFamilyDirectoryPath(const IDocument* pDocument);

        /// \brief 获取文档中载入的族文件的路径
        /// \param pDocument 文档的指针
        /// \param familyname 族文件名
        /// \return 文件路径
        static std::wstring GetFamilyFilePath(const IDocument* pDocument, const std::wstring& familyname);

        /// \brief 获取打开文档的临时文件路径
        /// \param pDocument 文档的指针
        /// \return 临时文件路径
        static std::wstring GetTempDirectoryPath(const IDocument* pDocument);

        /// \brief 获取带后缀的文件名
        /// \param pDocument 文档的指针
        /// \return 项目文件名
        static std::wstring GetProjectFileName(const IDocument* pDocument);

        /// \brief 获取产品自定义数据文件的路径
        ///
        /// 产品可以将自定义的数据文件放到该路径下，并会打包到最终的文件中,
        ///如果文件夹不存在，则创建，存在的话，直接返回文件夹路径
        /// \param pDocument 文档的指针
        /// \param directoryName 存放自定义数据文件的文件夹名称，产品可以自定义，为了区分不同的产品，该文件夹命名最好能体现各产品特色
        /// \return 文件路径
        static std::wstring GetCustomDataPath(const IDocument* pDocument, const std::wstring& directoryName);

        static std::wstring GetCustomDataFilePath(const IDocument* pDocument, const std::wstring& directory, const std::wstring & fileName);

        /// \brief 获取需要和模型数据一起保存的所有非模型数据的文件全路径
        /// \param pDocument 文档的指针
        /// \param checkOption 文件检查选项。此参数由调用者决定，在何种时机需要检测哪些文件。参数值由enum class NonModelFilesCheckOption按位运算得到。
        /// \                  如果选项为None，此时参数checkResult的传出值不可作为完整性判断条件。
        /// \param[out] checkResult 是否完整。外部传入时初值须为true，如果族文件缺失、材质文件缺失，此变量传出时返回false。
        /// \param[out] pErrorMessage 错误消息。如果传入不为空，在isIntergrated为false时，传出错误消息。
        /// \return 返回的文件全路径。需要检查checkResult和pErrorMessage
        static std::list<std::wstring> GetAllNonModelFilePaths(const IDocument* pDocument, int32_t checkOption, bool& checkResult, std::wstring* pErrorMessgae);
    
        /// \brief 暂存当前临时（未保存）项目名称，并设置新的项目名称为默认的文件1
        ///
        /// 目前主要用于日志系统
        /// \return void
        static void PushRuntimeContextAndReset();

        /// \brief 恢复之前暂存的临时（未保存）项目名称
        ///
        //. 目前主要用于日志系统，可见PushRuntimeContextAndReset()
        static void PopRuntimeContext();

        /// \brief 设置新的临时（未保存）项目名称
        /// \param IDocument* 文档指针
        /// \return 成功或失败
        static bool SetToUniqueTempProjectName(IDocument* pDocument);
    };
}

